/* COPYRIGHT_CHUNFENG */
#define ERROR_LOG_FILE "/tmp/log/cf_error.log"
#define MESSAGE_LOG_FILE "/tmp/log/cf_message.log"
#define DEBUG_LOG_FILE "/tmp/log/cf_debug.log"
#include "lcf_log.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <fcgi_stdio.h>
#include "cf_fcgi.h"
#include "cf_slist.h"
#include "string.h"


int CFFcgiResponseHead(CFContentType contentType)
{
    FCGI_printf("Content-Type:");
    switch(contentType){
        case CF_CONTENT_TYPE_TEXT_PLAIN:
            FCGI_printf("text/plain");
            break;
        case CF_CONTENT_TYPE_TEXT_HTML:
            FCGI_printf("text/html");
            break;
        default:
            FCGI_printf("application/binary");
    }
    FCGI_printf("\r\n\r\n");
    return 0;
}

int CFFcgiResponseErrorBody(int errorCode)
{
    FCGI_printf("{\"return\": %d}\n", errorCode);
    return 0;
}

int CFFcgiResponseOkBody()
{
    FCGI_printf("{\"return\": 200}\n");
    return 0;
}

int CFFcgiProcessGetRequest(const char* queryCStr, CFFCgiRequestKeyFuncPair* KeyFuncPairs)
{
    CFString * todoStr = cf_string_new("");
    int i;

    if(cf_cgi_parse_query(queryCStr, "todo", todoStr)){
        LCF_ERR("Can not find todo key in  query string\n");
        CFFcgiResponseHead(CF_CONTENT_TYPE_TEXT_PLAIN);
        CFFcgiResponseErrorBody(CF_CGI_RESPONSE_CODE_BAD_REQUEST);
        goto OUT_FREE_TODO_STRING;
    }
    for(i=0; KeyFuncPairs[i].todo; i++){
        if(!strcmp(KeyFuncPairs[i].todo, cf_string_get_str(todoStr))){
            if(KeyFuncPairs[i].authSessionUseQueryString){
                if(KeyFuncPairs[i].authSessionUseQueryString(queryCStr)){
                    goto OUT_FREE_TODO_STRING;
                }
            }
            if(!KeyFuncPairs[i].processUseQueryString){
                CFFcgiResponseHead(CF_CONTENT_TYPE_TEXT_PLAIN);
                CFFcgiResponseErrorBody(CF_CGI_RESPONSE_CODE_METHOD_NOT_ALLOWED);
                goto OUT_FREE_TODO_STRING;
            }else if(KeyFuncPairs[i].processUseQueryString(queryCStr)){
                goto OUT_FREE_TODO_STRING;
            }
            break;
        }
    }
    if(!KeyFuncPairs[i].todo){
        LCF_ERR("todo=%s not support\n", cf_string_get_str(todoStr));
        CFFcgiResponseHead(CF_CONTENT_TYPE_TEXT_PLAIN);
        CFFcgiResponseErrorBody(CF_CGI_RESPONSE_CODE_NOT_FOUND);
        goto OUT_FREE_TODO_STRING;
    }
    cf_string_free(todoStr);
    return 0;

OUT_FREE_TODO_STRING:
    cf_string_free(todoStr);
    return -1;
}

int CFFcgiProcessPostRequest(const char* postStr, CFFCgiRequestKeyFuncPair* KeyFuncPairs)
{
    CFJson *jReq;
    const char* todoCStr;
    int i;

    jReq = CFJsonParse(postStr);
    if(!jReq){
        LCF_ERR("Parse jsong req failed\n");
        CFFcgiResponseHead(CF_CONTENT_TYPE_TEXT_PLAIN);
        CFFcgiResponseErrorBody(CF_CGI_RESPONSE_CODE_BAD_REQUEST);
        goto OUT;
    }
    todoCStr = CFJsonObjectGetString(jReq, "todo");
    if(!todoCStr){
        LCF_ERR("todo key format is wrong\n");
        CFFcgiResponseHead(CF_CONTENT_TYPE_TEXT_PLAIN);
        CFFcgiResponseErrorBody(CF_CGI_RESPONSE_CODE_BAD_REQUEST);
        goto OUT_PARSE_JSON;
    }
    for(i=0; KeyFuncPairs[i].todo; i++){
        if(!strcmp(KeyFuncPairs[i].todo, todoCStr)){
            if(KeyFuncPairs[i].authSessionUseJason){
                        LCF_DBG("\n");
                if(KeyFuncPairs[i].authSessionUseJason(jReq)){
                                            LCF_DBG("\n");
                    goto OUT_PARSE_JSON;
                }
            }
            if(!KeyFuncPairs[i].processUseJason){
                                        LCF_DBG("\n");
                CFFcgiResponseHead(CF_CONTENT_TYPE_TEXT_PLAIN);
                CFFcgiResponseErrorBody(CF_CGI_RESPONSE_CODE_METHOD_NOT_ALLOWED);
                goto OUT_PARSE_JSON;
            }else if(KeyFuncPairs[i].processUseJason(jReq)){
                                        LCF_DBG("\n");
                goto OUT_PARSE_JSON;
            }
            break;
        }
    }
    if(!KeyFuncPairs[i].todo){
        LCF_ERR("todo=%s not support\n", todoCStr);
        CFFcgiResponseHead(CF_CONTENT_TYPE_TEXT_PLAIN);
        CFFcgiResponseErrorBody(CF_CGI_RESPONSE_CODE_NOT_FOUND);
        goto OUT_PARSE_JSON;
    }
    CFJsonPut(jReq);
    return 0;

OUT_PARSE_JSON:
    CFJsonPut(jReq);
OUT:
    return -1;
}

int CFFcgiProcessRequest(CFFCgiRequestKeyFuncPair* KeyFuncPairs)
{
    CFString* postStr = cf_string_new("");
    const char* queryCStr;
    const char* contentLenCStr;
    LCF_DBG("\n");
    queryCStr = getenv("QUERY_STRING");
    contentLenCStr = getenv("CONTENT_LENGTH");
        LCF_DBG("\n");
    if(!contentLenCStr && queryCStr && queryCStr[0]){
        LCF_DBG("\n");
        CFFcgiProcessGetRequest(queryCStr, KeyFuncPairs);
    }else if(contentLenCStr){
        LCF_DBG("\n");
        CFFcgiFpToString(postStr, FCGI_stdin, atoi(contentLenCStr));
                LCF_DBG("postStr: %s, contentLenCStr:%s\n", cf_string_get_str(postStr), contentLenCStr);
        CFFcgiProcessPostRequest(cf_string_get_str(postStr), KeyFuncPairs);
    }else{
        LCF_DBG("\n");
        CFFcgiResponseHead(CF_CONTENT_TYPE_TEXT_PLAIN);
        CFFcgiResponseErrorBody(CF_CGI_RESPONSE_CODE_BAD_REQUEST);
    }
    cf_string_free(postStr);
    return 0;
}

int CFFcgiFpToString(CFString* str, FCGI_FILE* fp, int len)
{
	char buf[512];
    int needRead = len;

    if(len == -1)
        needRead = sizeof(buf);
	while(1){
        int readed = FCGI_fread(buf, 1, needRead<sizeof(buf)?needRead:sizeof(buf), fp);
        if(len == -1)
            needRead = sizeof(buf);
        else
            needRead = needRead - readed;
        if(readed>0){
            cf_string_safe_cat_n(str, buf, readed);
        }
        if(!readed || !needRead || FCGI_feof(fp)) break;
    }
	return 0;
}
